using DotNetty.Transport.Channels;
using DotNetty.Buffers;
using DotNetty.Codecs;
using DotNetty.Common.Utilities;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using DotNetty.Transport.Bootstrapping;
using DotNetty.Transport.Channels.Sockets;

namespace AYO.Link.SocketBase
{
    public class TcpSocketClient
    {
        private IEventLoopGroup _group;
        private IChannel _channel;
        private Bootstrap _bootstrap;
        private string _host;
        private int _port;
        private Action<string> _onTextReceived;
        private List<Utf8Decoder> _decoders;
        private bool _isConnected;

        public TcpSocketClient(string host, int port, Action<string> onTextReceived)
        {
            _host = host;
            _port = port;
            _onTextReceived = onTextReceived;
            _decoders = new List<Utf8Decoder>();
            _isConnected = false;
        }

        public void AddDecoder(Utf8Decoder decoder)
        {
            _decoders.Add(decoder);
        }

        public async Task StartAsync()
        {
            _group = new MultithreadEventLoopGroup();
            _bootstrap = new Bootstrap()
                .Group(_group)
                .Channel<TcpSocketChannel>()
                .Option(ChannelOption.TcpNodelay, true)
                .Handler(new ActionChannelInitializer<IChannel>(channel =>
                {
                    var pipeline = channel.Pipeline;
                    foreach (var decoder in _decoders)
                    {
                        pipeline.AddLast(decoder);
                    }

                    pipeline.AddLast(new ClientHandler(_onTextReceived));
                }));

            await ConnectAsync();
        }

        private async Task ConnectAsync()
        {
            try
            {
                _channel = await _bootstrap.ConnectAsync(_host, _port);
                _isConnected = true;
            }
            catch (Exception ex)
            {
                HandleError(ex);
                Reconnect();
            }
        }

        private void Reconnect()
        {
            // 简单的重连策略
            Task.Delay(5000).ContinueWith(t =>
            {
                if (!_isConnected)
                {
                    Console.WriteLine("Reconnecting...");
                    StartAsync().Wait();
                }
            });
        }

        private void HandleError(Exception ex)
        {
            Console.WriteLine($"Error occurred: {ex.Message}");
        }

        public async Task SendAsync(string message)
        {
            if (_channel?.Active == true)
            {
                var buffer = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes(message));
                await _channel.WriteAndFlushAsync(buffer);
            }
            else
            {
                Console.WriteLine("Channel not connected.");
            }
        }

        public void Stop()
        {
            _isConnected = false;
            _channel?.CloseAsync();
            _group?.ShutdownGracefullyAsync();
        }
    }
}